package fr.generali.accueilclient.gwt.client.ui.components.form.formitem;

import com.google.gwt.editor.client.LeafValueEditor;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.TextBox;

import fr.generali.accueilclient.gwt.client.ui.components.form.formitem.handler.PreventNonNumericEntriesHandler;

public class SiretFormItem extends LabelFormItem<String> implements HasValue<String>, LeafValueEditor<String> {

    private SiretContainer siretContainer;

    public SiretFormItem() {
        super(new SiretContainer());
        siretContainer = (SiretContainer ) editableWidget;
        siretContainer.addStyleName(res.style().siretItem());
    }

    @Override
    protected boolean isDataFilled() {
        return siretContainer.isDataFilled();
    }

    @Override
    protected void doSetValue(String value, boolean valueIsNullOrEmpty) {
        if (!valueIsNullOrEmpty) {
            siretContainer.setSiren(value.substring(0, 9));
            siretContainer.setNic(value.substring(9, 14));
        }
        valueLabel.setText(value);
    }

    @Override
    protected boolean valueIsNullOrEmpty(String value) {
        return value == null || value.isEmpty();
    }

    private static class SiretContainer extends FlowPanel {

        private TextBox siren;

        private TextBox nic;

        SiretContainer() {

            siren = new TextBox();
            siren.setMaxLength(9);
            siren.setWidth("75px");
            siren.addKeyPressHandler(new PreventNonNumericEntriesHandler(siren));

            nic = new TextBox();
            nic.setMaxLength(5);
            nic.setWidth("45px");
            nic.addKeyPressHandler(new PreventNonNumericEntriesHandler(nic));

            add(siren);
            add(nic);
        }

        @Override
        public void addStyleName(String styleName) {
            siren.addStyleName(styleName);
            nic.addStyleName(styleName);
        }

        @Override
        public void removeStyleName(String style) {
            siren.removeStyleName(style);
            nic.removeStyleName(style);
        }

        void setSiren(String sirenValue) {
            siren.setValue(sirenValue);
        }

        void setNic(String nicValue) {
            nic.setValue(nicValue);
        }

        String getSiren() {
            return siren.getValue() != null ? siren.getValue() : "";
        }

        String getNic() {
            return nic.getValue() != null ? nic.getValue() : "";
        }

        boolean isDataFilled() {
            return !siren.getValue().isEmpty() && !nic.getValue().isEmpty();
        }

        public HandlerRegistration addSirenValueChangeHandler(ValueChangeHandler<String> handler) {
            return siren.addValueChangeHandler(handler);
        }

        public HandlerRegistration addNicValueChangeHandler(ValueChangeHandler<String> handler) {
            return nic.addValueChangeHandler(handler);
        }
    }

    @Override
    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
        siretContainer.addSirenValueChangeHandler(handler);
        return siretContainer.addNicValueChangeHandler(handler);
    }

    @Override
    public String getValue() {
        return siretContainer.getSiren() + siretContainer.getNic();
    }

    @Override
    public void setValue(String value, boolean fireEvents) {
        doSetValue(value, valueIsNullOrEmpty(value));
    }

    public boolean isValid() {
        return isValidSiren() && isValidSiret();
    }

    private boolean isValidSiren() {
        String siren = siretContainer.getSiren();
        if (siren.length() != 9) {
            return false;
        }
        return (sommeTab(provideIntTabFromString(siren, 1)) % 10) == 0;
    }

    private boolean isValidSiret() {
        String siret = siretContainer.getSiren() + siretContainer.getNic();
        if (siret.length() != 14) {
            return false;
        }
        return (sommeTab(provideIntTabFromString(siret, 0)) % 10) == 0;
    }

    private int sommeTab(int[] tab) {
        int somme = 0;
        for (int element : tab) {
            String sommeAsString = String.valueOf(element);
            for (int i = 0; i < String.valueOf(element).length(); i++) {
                somme += Integer.valueOf(sommeAsString.substring(i, i + 1));
            }
        }
        return somme;
    }

    private int[] provideIntTabFromString(String string, int startIndex) {
        int[] tab = new int[string.length()];
        for (int i = 0; i < string.length(); i++) {
            tab[i] = asInt(string, i) * (isPairNumber(i + startIndex) ? 2 : 1);
        }
        return tab;
    }

    private boolean isPairNumber(int i) {
        return i % 2 == 0;
    }

    private Integer asInt(String siren, int index) {
        return Integer.valueOf(siren.substring(index, index + 1));
    }
}
